package com.ccf.business.database.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.map.MapBuilder;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ccf.business.database.model.Datasource;
import com.ccf.business.database.model.vo.TableVO;
import com.service.database.action.JDBCExecutor;
import com.service.database.action.UrlAssembler;
import com.service.database.config.DataBase;
import com.service.database.config.DatabaseConfig;
import com.ccf.business.database.mapper.DatasourceMapper;
import com.service.database.model.DataModel;
import com.ccf.business.database.model.TableCache;
import com.ccf.business.database.service.IDatasourceService;
import com.ccf.business.database.service.ITableCacheService;
import com.common.model.pojo.Query;
import com.common.model.result.CodeEnum;
import com.common.model.result.PageResult;
import com.service.mybatis.pojo.SuperEntity;
import com.service.mybatis.service.impl.SuperServiceImpl;
import com.service.mybatis.util.Condition;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 
 *
 * @author ccf
 * @date 2021-11-25 16:42:29
 */
@Slf4j
@Service
public class DatasourceServiceImpl extends SuperServiceImpl<DatasourceMapper, Datasource> implements IDatasourceService {

    @Autowired
    private ITableCacheService tableCacheService;
    /**
    * 列表
    * @param query
    * @return
    */
    @Override
    public PageResult<Datasource> findList(Query query){
        Page<Datasource> page = page(Condition.getPage(query), Condition.getQueryWrapper(query));
        return PageResult.<Datasource>builder().datas(page.getRecords()).code(CodeEnum.SUCCESS.getCode()).count(page.getTotal()).build();
    }

    /**
     * 重写提交
     * @param datasource
     * @return
     */
    @Override
    public boolean submit(Datasource datasource) {
        //获取数据源类型
        DataBase dataBase = DataBase.toDataBase(datasource.getType());
        datasource.setDriver(dataBase.getDriver());

        //拼成url
        String url = UrlAssembler.UrlAssemblerBuilder.anUrlAssembler()
                .withDataBase(datasource.getType())
                .withHost(datasource.getHost())
                .withPort(datasource.getPort())
                .withDbName(datasource.getDatabaseName())
                .withSchema(datasource.getSchemaName())
                .build().createUrl();
        datasource.setUrl(url);

        return this.saveOrUpdate(datasource);
    }

    /**
     * 通过Id查询所有的表
     * @param id
     * @return
     */
    @Override
    public List listTables(String id) throws Exception {
        //获取数据库数据源配置
        Datasource datasource = this.getById(id);
        //获取表
        List<Map<String, Object>> tables = JDBCExecutor.listTables(getDatabaseConfig(datasource, null));
        List<Object> tableName = tables.stream().map(m -> m.get("tableName")).collect(Collectors.toList());
        return tableName;
    }

    @Override
    public List<String> listTablesBySelfBuilt(String id) throws Exception  {
        List<Object> list = listTables(id);
        QueryWrapper<TableCache> qw = new QueryWrapper<>();
        qw.eq("source_id", id);
        List<TableCache> tables = tableCacheService.list(qw);
        Set<String> names = tables.stream().map(e -> e.getTableName()).collect(Collectors.toSet());
        List<String> strList = list.stream().filter(Objects::nonNull).map(e->e.toString())
                .filter(e -> CollUtil.contains(names, e))
                .collect(Collectors.toList());
        return strList;
    }

    @Override
    public List<String> listTablesExcludeSelfBuilt(String id) throws Exception  {
        List<Object> list = listTables(id);
        QueryWrapper<TableCache> qw = new QueryWrapper<>();
        qw.eq("source_id", id);
        List<TableCache> tables = tableCacheService.list(qw);
        Set<String> names = tables.stream().map(e -> e.getTableName()).collect(Collectors.toSet());
        List<String> strList = list.stream().filter(Objects::nonNull).map(e->e.toString())
                .filter(e ->  !CollUtil.contains(names, e))
                .collect(Collectors.toList());
        return strList;
    }

    @Override
    public TableVO getTable(String id, String tableName, String page, String pageSize) throws Exception {
        //获取数据库数据源配置
        Datasource datasource = this.getById(id);
        DatabaseConfig config = getDatabaseConfig(datasource, tableName);

        //获取表信息
        List<Map<String, Object>> columns = JDBCExecutor.listTableDesc(config);
        Integer size = pageSize==null?Integer.MAX_VALUE:Convert.toInt(pageSize);
        Integer offset =   pageSize==null? 0 : (Convert.toInt(page) - 1) * Convert.toInt(pageSize);
        //获取表数据默认只取100条数据
        DataModel dataModel = JDBCExecutor.listTableDatas(getDatabaseConfig(datasource, tableName), size, offset);
        //获取表
        List<Map<String, Object>> tables = JDBCExecutor.listTables(getDatabaseConfig(datasource, null));
        Map<String, Object> tableInfo = tables.stream().filter(m -> m.get("tableName").equals(tableName)).findFirst().orElse(null);
        Object obj  =  tableInfo.get("createTime");
        LocalDateTime createTime = null;
        if(obj instanceof  LocalDateTime) {
            createTime = (LocalDateTime) obj;
        }  else if(obj instanceof Timestamp) {
            Timestamp timestamp = (Timestamp) obj;
            createTime = LocalDateTimeUtil.of(timestamp.getTime());
        }

        //构造VO返回对象
        TableVO tableVO = TableVO
                .builder()
                .columns(columns)
                .tableName(tableName)
                .count(dataModel.getCount())
                .datasourceName(datasource.getName())
                .dbname(datasource.getDatabaseName())
                .datas(dataModel.getDatas())
                .comment((String) tableInfo.getOrDefault("comment", ""))
                .createTime(createTime == null ? "" : DateUtil.format(createTime, "yyyy-MM-dd HH:mm:ss"))
                .build();
        return tableVO;
    }

    @Override
    public List<Map<String, Object>> getTableDesc(String id, String tableName) throws Exception {
        //获取数据库数据源配置
        Datasource datasource = this.getById(id);
        DatabaseConfig config = getDatabaseConfig(datasource, tableName);

        //获取表信息
        List<Map<String, Object>> columns = JDBCExecutor.listTableDesc(config);
        return columns;
    }

    @Override
    public DataModel getTableData(String id, String tableName, Integer pageSize, Integer page) throws Exception {
        //获取数据库数据源配置
        Datasource datasource = this.getById(id);

        DataModel dataModel = JDBCExecutor.listTableDatas(getDatabaseConfig(datasource, tableName),
                Convert.toInt(pageSize), Convert.toInt(page));
        //获取表信息
        return dataModel;
    }

    /**
     * 测试数据库连接
     * @param datasource
     * @return
     */
    @Override
    public boolean connect(Datasource datasource) {
        DatabaseConfig config = getDatabaseConfig(datasource, null);
        return JDBCExecutor.testConnect(config);
    }

    @Override
    public List searchTables(String keyword, String datasourceId) throws Exception {
        //返回结果
        List<Map<Object, Object>> result = new ArrayList<>();

        //获取所有的数据源
        List<Datasource> datasources = this.list(Wrappers.<Datasource>lambdaQuery().eq(StrUtil.isNotEmpty(datasourceId), SuperEntity::getId, datasourceId));
        for (Datasource ds : datasources) {
            List<String> tables = this.listTables(ds.getId());

            List<Map<Object, Object>> tableMaps = tables.stream().map(table -> MapBuilder.create().put("tableName", table.toString()).put("highTableName", table.toString()).put("datasourceId", ds.getId()).build()).collect(Collectors.toList());
            if(StrUtil.isNotEmpty(keyword)) {
                tableMaps = tableMaps.stream().filter(table -> Convert.toStr(table.get("highTableName")).contains(keyword)).peek(table -> table.put("highTableName", Convert.toStr(table.get("highTableName")).replaceAll(keyword, "<em>"+keyword+"</em>"))).collect(Collectors.toList());
            }
            result.addAll(tableMaps);
        }

        return result;
    }

    /**
     * 将数据库中的Datasource转换成DatabaseConfig
     * @param datasource
     * @return
     */
    private DatabaseConfig getDatabaseConfig(Datasource datasource, String tableName){
        //构造配置
        DatabaseConfig.DatabaseConfigBuilder builder = DatabaseConfig
                .DatabaseConfigBuilder
                .aDatabaseConfig()
                .withType(datasource.getType())
                .withIp(datasource.getHost())
                .withPort(datasource.getPort())
                .withDbName(datasource.getDatabaseName())
                .withSchema(datasource.getSchemaName())
                .withUserName(datasource.getUserName())
                .withUserPwd(datasource.getPwd())
                .withSchema(datasource.getSchemaName())
                .withDriver(DataBase.toDataBase(datasource.getType()).getDriver());

        //设置表信息
        if(StrUtil.isNotEmpty(tableName)){
            builder.withTableName(tableName);
        }

        //重新生成URL
        return  builder.resetUrlAndBuild();
    }

    @Override
    public List searchFieldValue(String id, String tableName, String fieldName) {
        Datasource datasource = this.getById(id);
        DatabaseConfig config = getDatabaseConfig(datasource, tableName);
        try {
            List<Object> objects = JDBCExecutor.distinctCol(config, fieldName);
            return objects;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
